Terraform 1.10がGAになり、Ephemeral Valuesが使えるようになりました
2024/11/27にTerraformのVersion 1.10がGAになりました!
1.10より Ephemeral valuesという機能が利用可能になりました。この新機能の詳細を見ていきましょう。
概要
ざっくりとは、機密情報をTerraformで扱う際に利用する機能です。
例えばデータベースインスタンスをTerraformで管理しようとした場合、そのパスワード(=機密情報)の値は他のattributeと同様TerraformのStateファイルに保存されます。また terraform plan
コマンドに -out
オプションをつけると生成されるplanファイルにも保存されます。
これらStateファイルやplanファイルが万が一外部に漏洩した場合、それはデータベースパスワードが漏洩したことになり、大きなセキュリティリスクです。
そのため従来はこのリスクの対策として、例えばリソース作成した後にTerraform外でパスワード値を更新し、パスワードattributeをignore_changes に指定するといった方法がありました。
- ※ 蛇足ですが、この ignore_changes対策方法は扱うリソースのattributeによっては対策にならない場合があるので注意です。詳しくは [Terraform] 誤解されがちなignore_changesの動き・機密情報はstateに保持されるのか? | DevelopersIOをご確認ください。
今回登場したEphemeral valuesがこのセキュリティリスクを緩和します。Ephemeral valuesは、Stateファイル・planファイルに 保存されない 値です。
Ephemeral valuesは以下の5機能に分割できます。
- Ephemeral input variables
- Ephemeral output variables
- Ephemeral resources
- ephemeralasnull 関数
- write-only attribute
- write-only attributeは 次Version 1.11 でリリース予定です。 1.10には含まれていません。
それぞれ説明します。
Ephemeral input variables
variableブロックにephemeral
attributeが追加されました。
variable "hoge" {
type = string
ephemeral = true
}
ephemeral = true
と設定されたvariableは、現在のオペレーション(現在のterraform plan
もしくはterraform apply
の実行のことだと思われます)でのみ使用され、Stateファイルやplanファイルには記録されません。
この ephemeral variable(=ephemeral = true
と設定されたvariable)は参照できる場所が以下に限られています。
- 他の ephemeral variable
- v1.9より、variableのvalidationブロック内で他のvariableを参照できるようになりました。 (参考)
そこで使うことを想定していると思われます。
- v1.9より、variableのvalidationブロック内で他のvariableを参照できるようになりました。 (参考)
- local value
- ephemeral variableを参照したlocal value も自動的に ephemeral value扱いになります。つまりここのリストに書かれているものからしか参照できなくなります。
- ephemeral resource (後述)
- ephemeral output (後述)
要は参照先もephemeralである必要があるということですね。これ以外で参照しようとするとエラーになります。
variable "test-ephemeral" {
type = string
default = "test"
ephemeral = true
}
resource "aws_s3_bucket" "main" {
bucket_prefix = var.test-ephemeral
}
% terraform plan
╷
│ Error: Invalid use of ephemeral value
│
│ with aws_s3_bucket.main,
│ on main.tf line 2, in resource "aws_s3_bucket" "main":
│ 2: bucket_prefix = var.test-ephemeral
│
│ Ephemeral values are not valid in resource arguments, because resource instances must persist between Terraform phases.
Ephemeral output variables
variableブロック同様にoutputブロックにもephemeral
attributeが追加されました。
output "fuga" {
value = aws_secretsmanager_secret.secret_id
ephemeral = true
}
このephemeral
attributeは、child module のアウトプットでのみ使用できます。
root モジュールのoutputには使えません。
以下はroot モジュールのoutputで使ってみた例です。エラーになります。
output "test" {
value = "test"
ephemeral = true
}
% terraform plan
│
│ Error: Ephemeral output not allowed
│
│ on outputs.tf line 1:
│ 1: output "test" {
│
│ Ephemeral outputs are not allowed in context of a root module
エラーになるのは理にかなっています。root モジュールでoutputにするということは、terraform_remote_state
データソースを使って参照するような用途が想定されます。terraform_remote_state
データソースで使うにはStateファイルに値を記録する必要があり、これはephemeral valuesのコンセプトから外れます。
また、ephemeral variableと同様、ephemeral outputも参照できる箇所が限られています。
- ephemeral resource (後述)
- ephemeral variable
- 他のchild moduleのephemeral output
Ephemeral resources
ephemeral valuesの本丸です。ephemeral variableもephemeral outputもこのephemeral リソースと連携することを想定しているので。
ephemeral
ブロックが追加されました。こちらのブロックでephemeral リソースを定義します。中に定義する内容は従来のresourceブロックとほぼ同じです。
ephemeral "<resource_type>" "<resource_name>" {
<attributes>
<meta-arguments>
}
また、ephemeral リソースのattributesも variableやoutputと同様参照できる箇所が限られています。
- 他のephemeral リソース
- local values (ephemeral value扱いになる)
- ephemeral variable
- ephemeral output
- provider block(プロバイダーの設定)
- provisioner や connection block
ephemeral リソース使用例が以下です。aws_secretsmanager_secret_version
がephemeralリソースですね。従来だとこの部分は aws_secretsmanager_secret_version
データソースでやっていたと思うのですが、その場合その中身がStateファイルやplanファイルに記録されてしまっておりました。
provider "aws" {
region = "eu-west-2"
}
data "aws_db_instance" "example" {
db_instance_identifier = "testdbinstance"
}
ephemeral "aws_secretsmanager_secret_version" "db_master" {
secret_id = data.aws_db_instance.example.master_user_secret[0].secret_arn
}
locals {
credentials = jsondecode(ephemeral.aws_secretsmanager_secret.db_master.secret_string)
}
provider "postgresql" {
host = data.aws_db_instance.example.address
port = data.aws_db_instance.example.port
username = local.credentials["username"]
password = local.credentials["password"]
}
resource "postgresql_database" "db" {
name = "new_db"
}
AWS providerのEphemeral resources
AWS Proverのv5.77.0でこれらEphemeral resourcesが追加されています。ですのでTerraform本体のバージョンを1.10にしたうえで、AWS Providerのバージョンも5.77.0以上に上げましょう。
aws_secretsmanager_secret_version
Secrets Manager secretの特定のversionを取得するephemeralリソースです。secretのvalueをsecret_string
に持ちます。
こちらが一番使用されるephemeralリソースになるのではないかと思います。
aws_kms_secrets
KMSで暗号化されたデータから複数のシークレットを復号化するephemeralリソースです。
使用方法は既存の aws_kms_secrets
データソース と同じのようです。Stateファイルやplanファイルに記録されない分、今後はephemeral版の使用を第一に検討しましょう。
aws_lambda_invocation
Lambda関数の実行を行なうリソースです。
ユースケースが思い浮かばなかったのですが、上記ドキュメントに記載がありました。
The aws_lambda_invocation ephemeral resource invokes the function during every plan and apply when the function is known. A common use case for this functionality is when invoking a lightweight function—where repeated invocations are acceptable—that produces sensitive information you do not want to store in the state.
毎planとapplyでLambda関数が実行されるんですね。外部から機密情報をLambda関数経由で取得して、結果をSecrets Manager secretに登録する、みたいな用途で使われるのでしょうか。
ちなみに、ephemeralじゃないaws_lambda_invocation リソースの関数実行タイミングは、triggers
を設定していない限りはapplyで当該リソースが作成された際と、 replaceが発生する際のみです。関数実行タイミングが違うので注意です。
ephemeralasnull 関数
ephemeral as null
ということで、ephemeral valueをnull値に変換する関数です。
「いつ使うんや?」と思いましたが、ephemeralasnull 関数のドキュメントページでは以下ユースケースが紹介されていました。
variable "session_token" {
type = string
default = "test"
ephemeral = true
}
variable "configuration" {
type = map(string)
default = {
"env" = "development"
}
}
# This is a contrived example, but this pattern works with any object that is a mix of ephemeral and non-ephemeral values.
locals {
configuration_with_token = merge(
var.configuration,
{ "session_token" = var.session_token }
)
}
output "configuration_settings" {
# Using ephemeralasnull enables you to output the non-ephemeral values.
value = ephemeralasnull(local.configuration_with_token)
description = "Environment setting."
}
要は、ephemeral valueを含むvalueを非 ephemeral valueで参照したい場合です。
これまで説明したとおり、ephemeral value は参照できる箇所が限られています。 ephemeralasnull関数を通すことで、その参照可能箇所外でも参照できるようになります。ただしephemeral value値はnullに変換されます。
上記コードをapplyした後のoutputは以下になります。
% terraform output
configuration_settings = {
"env" = "development"
"session_token" = tostring(null)
}
session_token
は ephemeral variable である session_token
を参照しているのでephemeral valueであり、configuration_settings
全体が ephemeral value扱いになります。ですので、configuration_settings
outputに ephemeral = true
を付与する必要がありますし、もしこれがrootモジュールなのであればそれでも「root モジュールのoutputはephemeral化できない」という制約に引っかかりエラーになります。ephemeralasnull関数を通すことでこの問題を回避しています。
まだ 1.10へのアップグレードは待ったほうがいいかも
2024/12/04時点で 1.10のタグのついたissueは全てクローズになっています。これらの修正が盛り込まれた 1.10.1リリースを待つほうが良いと思います。
参考情報
- Terraform 1.10 improves handling secrets in state with ephemeral values
- Release v1.10.0 · hashicorp/terraform
- Upgrading to Terraform v1.10 | Terraform | HashiCorp Developer
- Exclude values from state - Input Variables - Configuration Language | Terraform | HashiCorp Developer
- ephemeral — Avoid storing values in state or plan files - Output Values - Configuration Language | Terraform | HashiCorp Developer
- Ephemeral values - Local Values - Configuration Language | Terraform | HashiCorp Developer
- Ephemeral resource configuration reference | Terraform | HashiCorp Developer
- ephemeralasnull function reference - Functions - Configuration Language | Terraform | HashiCorp Developer